package com.translate.web.api.logic.impl;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.translate.web.api.enums.OrderNodeEnums;
import com.translate.web.api.service.IMgOrderNodeRecordService;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.common.util.ListConvertMap;
import com.common.util.SnowFlake;
import com.returns.value.CodeAndData;
import com.returns.value.ICodeAndData;
import com.translate.entity.Manuscript;
import com.translate.entity.NoticeCenter;
import com.translate.entity.Order;
import com.translate.entity.OrderLog;
import com.translate.entity.PayManager;
import com.translate.entity.ServiceManager;
import com.translate.entity.ServicePriceConf;
import com.translate.entity.Team;
import com.translate.entity.User;
import com.translate.vo.ServiceManagerVO;
import com.translate.web.api.logic.IPlanceOrderLogic;
import com.translate.web.config.contract.IOSSConfig;
import com.translate.web.constant.EditStatus;
import com.translate.web.constant.NotificationType;
import com.translate.web.constant.OrderErrorMsg;
import com.translate.web.constant.OrderStatus;
import com.translate.web.constant.RedisConstant;
import com.translate.web.constant.UserStatus;
import com.translate.web.param.IdAndUserIdParam;
import com.translate.web.param.contract.IIdAndUserIdParam;
import com.translate.web.param.contract.IManuscriptAddParam;
import com.translate.web.param.contract.IPayManagerAddParam;
import com.translate.web.param.contract.IPayManagerServiceAddParam;
import com.translate.web.service.IManuscriptService;
import com.translate.web.service.INoticeCenterService;
import com.translate.web.service.IOrderLogService;
import com.translate.web.service.IOrderService;
import com.translate.web.service.IPayManagerService;
import com.translate.web.service.IPayTypeService;
import com.translate.web.service.IServiceManagerService;
import com.translate.web.service.IServicePriceConfService;
import com.translate.web.service.ITeamService;
import com.translate.web.service.IUserService;
import com.util.OrderNumberGenerator;

@Component
public class PlanceDetailLogic implements IPlanceOrderLogic {

	Logger logger = LoggerFactory.getLogger(PlanceDetailLogic.class);

	IOSSConfig config;

	private IPayManagerService service;

	IOrderService orderService;

	IOrderLogService orderLogService;

	IPayTypeService payTypeService;

	IUserService userService;

	IServicePriceConfService priceConfService;

	IManuscriptService manuscriptService;

	IServiceManagerService serviceManager;

	ITeamService teamService;

	INoticeCenterService centerService;

	PlatformTransactionManager platformTransactionManager;

	@Resource
	private IMgOrderNodeRecordService iMgOrderNodeRecordService;


	@Resource
	public void setServiceManager(IServiceManagerService serviceManager) {
		this.serviceManager = serviceManager;
	}

	@Resource
	public void setCenterService(INoticeCenterService centerService) {
		this.centerService = centerService;
	}

	@Resource
	public void setTeamService(ITeamService teamService) {
		this.teamService = teamService;
	}

	@Resource
	public void setConfig(IOSSConfig config) {
		this.config = config;
	}

	@Resource
	public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
		this.platformTransactionManager = platformTransactionManager;
	}

	@Resource
	public void setOrderLogService(IOrderLogService orderLogService) {
		this.orderLogService = orderLogService;
	}

	@Resource
	public void setManuscriptService(IManuscriptService manuscriptService) {
		this.manuscriptService = manuscriptService;
	}

	public PlanceDetailLogic(IPayManagerService service) {
		this.service = service;
	}

	@Resource
	public void setOrderService(IOrderService orderService) {
		this.orderService = orderService;
	}

	@Resource
	public void setPayTypeService(IPayTypeService payTypeService) {
		this.payTypeService = payTypeService;
	}

	@Resource
	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	@Resource
	public void setPriceConfService(IServicePriceConfService priceConfService) {
		this.priceConfService = priceConfService;
	}

	/**
	 * 方法 返回值
	 */
	class Result {
		boolean useConpon;

		Order[] orders;

		/**
		 * 只有查重？
		 */
		boolean onlyDuplicateCheck;

		BigDecimal totalPrice;

		int duplicateCheckCoupon;

	}

	// 格式 0 latex 1 word
	static int[] FORMATER = new int[] { 28, 29, };

	public <P extends IPayManagerServiceAddParam> BigDecimal getWordSize(P p) {

		Integer wordSize = p.getWordSize();
		if (null == wordSize) {
			return null;
		}

		return new BigDecimal(wordSize);

	}

	/**
	 *
	 * @param <P>           订单参数
	 * @param <M>           稿件
	 * @param itemService   当前购买的服务
	 * @param listFromCache 服务价格配置
	 * @param user          用户
	 * @param snowFlake     订单雪花算法
	 * @param statusCode    订单状态
	 * @param type          服务类型 0 基础服务 1 数据作图与科研绘图服务
	 * @return
	 */
	private <P extends IPayManagerServiceAddParam> Result generateOrdersList(IPayManagerAddParam payManagerAddParam,
			P[] itemService, Map<Integer, List<ServicePriceConf>> listFromCache, User user, SnowFlake snowFlake,
			byte statusCode, byte type, String orderNumber) {

		if (null == itemService) {
			return new Result();
		}

		ServicePriceConf servicePriceConf = null, tmp;

		BigDecimal totalPrice = new BigDecimal(0), zero = new BigDecimal(0);

		BigDecimal onehandruid = new BigDecimal(100);

		BigDecimal wordSizePrice = BigDecimal.ZERO, customerPrice;

		Order[] order = new Order[itemService.length];

		Order item;

		Byte urgent, lazy = 0;

		long time = System.currentTimeMillis() / 1000;

		boolean useConpon = false;

		byte zeroStatus = 0;

		P p;

		Integer duplicateCheckCoupon = user.getDuplicateCheckCoupon();

		BigDecimal discountByUser = user.getDiscount();

		Integer teamId = user.getTeamId();

		if (null != teamId && 0 < teamId) {
			// 加入团队了 使用团队折扣

			IIdAndUserIdParam param = new IdAndUserIdParam();

			param.setId(teamId);

//			param.setUserId(user.getId());

			Team dataDetailFromCache = teamService.getDataDetailFromCache(param, RedisConstant.getTeamKey(teamId), 6);

			discountByUser = dataDetailFromCache.getDiscount();
		}

		BigDecimal wordSizeB, servicePrice = BigDecimal.ZERO, urgentMoney = BigDecimal.ZERO, actualPaidPrice;

		int num = itemService.length;

		// 28 -> 论文排版(word)
		// 29 -> 论文排版(Latex)

		Integer serviceId;

		List<ServicePriceConf> servicePriceConfs;

		int size;

		PriceData priceData;

		for (int i = 0; i < itemService.length; i++) {

			p = itemService[i];

			Byte format = p.getFormat();

			serviceId = p.getServiceId();

			servicePriceConfs = listFromCache.get(serviceId);

			if (servicePriceConfs == null) {
				continue;
			}

			Integer wordSize = p.getWordSize();
			size = servicePriceConfs.size();

			item = new Order();

			// 1 单论翻译 2 学术翻译
			if (1 == serviceId || 2 == serviceId) {
				priceData = gradientCharging(p, servicePriceConfs, item);

				wordSizePrice = priceData.wordSizePrice;

				servicePrice = priceData.servicePrice;

				logger.debug("翻译：wordSizePrice: {}, servicePrice: {}", wordSizePrice, servicePrice);

			} else if (1 == size) {
				// 专家预审
				servicePriceConf = servicePriceConfs.get(0);

				priceData = setOrderAndComputerPrice(p, servicePriceConf, item, getWordSize(p));

				wordSizePrice = priceData.wordSizePrice;

				servicePrice = priceData.servicePrice;

				logger.debug("其他服务：wordSizePrice: {}, servicePrice: {}", wordSizePrice, servicePrice);
			} else  {

				if (null != format) { // 论文排版
					serviceId = FORMATER[format];

					Map<Integer, ServicePriceConf> listToMap = ListConvertMap.listToMap(servicePriceConfs,
							ServicePriceConf::getId);

					servicePriceConf = listToMap.get(serviceId);

					priceData = setOrderAndComputerPrice(p, servicePriceConf, item, getWordSize(p));

					wordSizePrice = priceData.wordSizePrice;

					servicePrice = priceData.servicePrice;

					logger.debug("排版：wordSizePrice: {}, servicePrice: {}", wordSizePrice, servicePrice);

				} else {
					// 论文查重
					Integer servicePriceId = p.getServicePriceId();


					for (ServicePriceConf conf : servicePriceConfs) {

						if (0 == conf.getId().compareTo(servicePriceId)) {
							servicePriceConf = conf;
						}
					}

					if (null == servicePriceConf) {
						throw new Error("找不到价格配置");
					}

					wordSizePrice = servicePriceConf.getCustomerPrice();

					item.setServiceTypeName(servicePriceConf.getServiceType());

					item.setHavaTranslationProof(servicePriceConf.getHavaTranslationProof());

					servicePrice = wordSizePrice;
				}

			}

			item.setDiscount(discountByUser);



//			customerPrice = servicePriceConf.getCustomerPrice();

			// 是否加急
//			urgent = p.getUrgent();


			// 查重券？
			if (1 == p.getUseCoupon() && 1 == servicePriceConf.getUseCheckCoupon()) {

//				BigDecimal wordSizeB3 = BigDecimal.valueOf(wordSize);
//				wordSizePrice = customerPrice.multiply(wordSizeB3);
				if (1 <= duplicateCheckCoupon) {
					duplicateCheckCoupon -= 1;
					statusCode = OrderStatus.PENDING_CONFIRMATION.getStatusCode();
					// 抵扣金额
					useConpon = true;
					item.setUseCheckConpon((byte) 1);
					item.setCouponDeductible(wordSizePrice);
					wordSizePrice = zero;
				}
			} else {
				item.setCouponDeductible(zero);
			}


			actualPaidPrice = wordSizePrice.multiply(discountByUser).divide(onehandruid);

			// 计算 总价 = 服务价格 + 加急费用 + 起步价 - 抵扣金额
			totalPrice = totalPrice.add(actualPaidPrice);

			// 实际支付价格 = 总价 * 折扣

			item.setActualPaidPrice(actualPaidPrice);

//			logger.debug("总价: {}, 实际支付价格: {}", totalPrice, item.getActualPaidPrice());

			Integer assocId = payManagerAddParam.getAssocId();

			if (null != assocId && 0 != assocId) {
				item.setServiceStatus((byte) 3);
			} else {
				item.setServiceStatus(zeroStatus);
			}

			item.setAssocId(assocId);

			if (1 < num) {
				String suffix = i < 10 ? "-0" : "-";
				item.setOrderSnId(orderNumber + suffix + (i + 1));
			} else {
				item.setOrderSnId(orderNumber);
			}

			item.setTotalPrice(wordSizePrice);

			createOrderItem(user, servicePrice, item, time, statusCode, snowFlake, zeroStatus, p, wordSize, type,
					p.getServiceId());
			order[i] = item;
		}

		Result result = new Result();

		if (1 == order.length && useConpon) {

			if (7 == order[0].getServiceId()) {
				result.onlyDuplicateCheck = true;
			}

		}

		result.orders = order;

		result.totalPrice = totalPrice;

		result.useConpon = useConpon;

		result.duplicateCheckCoupon = duplicateCheckCoupon;

		return result;

	}


	/**
	 * 设置订单属性及价格
	 * @param <P>
	 * @param p
	 * @param servicePriceConf
	 * @param item
	 * @return
	 */
	protected <P extends IPayManagerServiceAddParam> PriceData setOrderAndComputerPrice(P p,
			ServicePriceConf servicePriceConf,
			Order item,
			BigDecimal wordSize
	) {

		// 是否加急
		Byte urgent = p.getUrgent(), lazy = 0;

		BigDecimal wordSizeB;
		BigDecimal customerPrice = servicePriceConf.getCustomerPrice();;
		BigDecimal onehandruid = new BigDecimal(100);
		BigDecimal urgentMoney = BigDecimal.ZERO;
		BigDecimal servicePrice;
		BigDecimal wordSizePrice;
//		if (null != urgent && 1 == urgent && 1 == servicePriceConf.getUrgent()) {
//
//			// 加收比例
//			BigDecimal additionalChargeRatio = BigDecimal
//					.valueOf(servicePriceConf.getAdditionalChargeRatio().doubleValue());
//
//			// 新价格 =》 0.25(1+0.5) - 0.25;
////			BigDecimal additionalChargeRatioNew = additionalChargeRatio.add(onehandruid).divide(onehandruid)
////					.multiply(customerPrice);
////
////			wordSizePrice = additionalChargeRatioNew.multiply(wordSizeB);
//
//
//			wordSizeB = wordSize;
//
//			urgentMoney = additionalChargeRatio.multiply(wordSizeB).multiply(customerPrice).divide(onehandruid);
//
//			servicePrice = customerPrice.multiply(wordSizeB);
//
//			wordSizePrice = servicePrice.add(urgentMoney);
//
//			logger.debug("urgentMoney: {}", urgentMoney);
//
//			item.setUrgentMoney(urgentMoney);
//			item.setUrgent(urgent);
//
//		} else {

			Byte billingMethod = servicePriceConf.getBillingMethod();

			wordSize = null == wordSize ? BigDecimal.ZERO : wordSize;

			// 客服报价
			if (0 == billingMethod.compareTo((byte) 2)) {
				wordSizePrice = servicePrice = p.getPrice();
			} else {

				wordSizeB = wordSize;

				servicePrice = customerPrice.multiply(wordSizeB);

				wordSizePrice = servicePrice;

				// 获取起步价
				BigDecimal startPrice = servicePriceConf.getStartPrice();

				// 起步价不为空，并且起步价高于字数价格则采用起步价
				if (null!= startPrice && wordSizePrice.compareTo(startPrice) == -1) {
					wordSizePrice = startPrice;
				}
			}

			item.setUrgent(lazy);

			item.setUrgentMoney(urgentMoney);
//		}

		item.setServiceTypeName(servicePriceConf.getServiceType());

		item.setHavaTranslationProof(servicePriceConf.getHavaTranslationProof());

		PriceData priceData = new PriceData();

		priceData.servicePrice = servicePrice;

		priceData.wordSizePrice = wordSizePrice;
		return priceData;

	}

	private static class PriceData {

		public BigDecimal servicePrice= BigDecimal.ZERO;

		public BigDecimal wordSizePrice = BigDecimal.ZERO;

	}

	/**
	 * 梯度收费
	 * @param <P>
	 * @param servicePriceConf
	 * @param p
	 * @param servicePriceConfs
	 * @param size
	 * @param wordSize
	 * @return 收费价格
	 */
	protected <P extends IPayManagerServiceAddParam> PriceData gradientCharging(P p,
			List<ServicePriceConf> servicePriceConfs,
			Order order) {

		ServicePriceConf tmp = null;

		Integer wordSize = p.getWordSize();
		if (null == wordSize) {
			throw new Error( "字数不能为零");
		}

		int realSize = wordSize.intValue();

		servicePriceConfs = servicePriceConfs
				.stream()
				.filter(item -> 0 == item.getProgramme().compareTo(p.getProgramme()))
				.filter(item -> item.getStart().intValue() <= realSize)
				.collect(Collectors.toList());

		servicePriceConfs.sort((f,s) -> f.getStart().compareTo(s.getStart()));

		// 使用区间计算

		BigDecimal bigDecimalWordSize = null;

		BigDecimal totalPrice = BigDecimal.ZERO;

		// 梯度收费

		PriceData result = new PriceData();

		int size = servicePriceConfs.size();
		for (int k = 0; k < size; k++) {

			tmp = servicePriceConfs.get(k);

			int start = tmp.getStart().intValue();

			int end = tmp.getEnd().intValue();

			if (0 == tmp.getType()) { // 区间

				// 8 < 9 < 10
				// 1 	5000   \
				// 		         6000
				// 5001 8000  /

				// 8001 - 10000
				// 10001 - 无穷   15000
				if (end <= realSize) {

					// 再区间内
					bigDecimalWordSize = new BigDecimal(end - start + 1);
				}  else if (start < realSize && realSize < end) {
					// 在下一个区间
					bigDecimalWordSize = new BigDecimal(realSize - start + 1);
				}


				PriceData priceData = setOrderAndComputerPrice(p, tmp, order, bigDecimalWordSize);

				result.wordSizePrice = result.wordSizePrice.add(priceData.wordSizePrice);

				result.servicePrice = result.servicePrice.add(priceData.servicePrice);

			} else  {
				if (wordSize >= start) {
					bigDecimalWordSize = new BigDecimal(realSize - start + 1);
					totalPrice = totalPrice.add(bigDecimalWordSize.multiply(tmp.getCustomerPrice()));
				}
				break;
			}
		}

		if (null == tmp) {
			throw new IllegalArgumentException("服务价格配置异常");
		}
		return result;
	}

	private static class OrderResult {
		OrderErrorMsg errorMsg;

		int[] orderIds;

		int id;
	}

	/**
	 * 基础服务
	 *
	 * @param listFromCache
	 * @param userInfoToCache
	 * @param snowFlake
	 * @param type            服务类型 0 基础服务 1 数据作图与科研绘图服务
	 *
	 */
	private <P extends IPayManagerServiceAddParam, M extends IManuscriptAddParam> OrderResult basicServices(
			IPayManagerAddParam<P, M> payManagerAddParam, Map listFromCache, User userInfoToCache, SnowFlake snowFlake,
			byte type,boolean useConpon) {
		P[] itemService = payManagerAddParam.getItemService();

		OrderResult orderResult = new OrderResult();

		if (null == itemService || 0 == itemService.length) {

			orderResult.errorMsg = OrderErrorMsg.SUCCESS;

			return orderResult;
		}

		M[] manuscripts = payManagerAddParam.getManuscripts();

		if (null == manuscripts || 0 == manuscripts.length) {
			orderResult.errorMsg = OrderErrorMsg.BASIC_SERVICES_MANUSCRIPTS;
			return orderResult;
		}

		int userId = payManagerAddParam.getUserId();

		// 计算单、多轮润色及 单、多轮翻译 字数价格
		byte statusCode = OrderStatus.PENDING_PAYMENT.getStatusCode();
		;

		// 验证字数 及 篇数 不能 为 0

		for (P p : itemService) {

			if (null == p.getWordSize() && 7 != p.getServiceId()) {
				orderResult.errorMsg = OrderErrorMsg.BASIC_SERVICES_WORD_SIZE;
				return orderResult;
			}
		}

		String orderNumber = OrderNumberGenerator.generateOrderNumber("ZF");

		Result result = generateOrdersList(payManagerAddParam, itemService, listFromCache, userInfoToCache, snowFlake,
				statusCode, type, orderNumber);

		Order[] ordersList = result.orders;

		long time = System.currentTimeMillis() / 1000;

		if (null == ordersList || 0 == ordersList.length) {
			orderResult.errorMsg = OrderErrorMsg.NO_BASIC_SERVICE_ORDERS;
			return orderResult;
		}

		// 添加 支付 管理

		PayManager payManager = new PayManager();

		payManager.setCreateTime(time);

		payManager.setOrderSnId(orderNumber);

		payManager.setPayType(payManagerAddParam.getPayType());

		payManager.setUserId(payManagerAddParam.getUserId());

		payManager.setPriceSum(result.totalPrice);
		if(result.useConpon){
			payManager.setUseCheckConpon((byte)1);
		}

//		logger.debug("总价: {}", result.totalPrice);

		byte orderStatus = 0;
		payManager.setOrderStatus(orderStatus);

		Integer teamId = userInfoToCache.getTeamId();

		if (1 != userInfoToCache.getStatus()) {
			teamId = 0;
		}

		payManager.setTeamId(teamId);

		payManager.setTranslate(orderStatus);

		payManager.setUpdateTime(time);

		List<ServiceManager> listToCache = this.serviceManager.listToCache(RedisConstant.SERVICCE_MANGER_KEY, 11);

		Map<Integer, ServiceManager> listToMap = ListConvertMap.listToMap(listToCache, ServiceManager::getId);

		StringBuilder serviceNames = new StringBuilder();

		for (int i = 0; i < ordersList.length; i++) {
			serviceNames.append(listToMap.get(ordersList[i].getServiceId()).getTypeName()).append("+");
		}

		String res = serviceNames.substring(0, serviceNames.length() - 1);

		payManager.setServiceNames(res);

		if (result.onlyDuplicateCheck) {
			// 只有论文查重且使用了查重券
			payManager.setOrderStatus((byte) 1);
		}

		service.insert(payManager);

		Integer id = payManager.getId();
		setPayManagerIdBYOrder(ordersList, id);

		orderService.batchInsert(ordersList);




		// 处理通知 ----------------------------------------------------------------
//		NoticeCenter[] notices = new NoticeCenter[ordersList.length];

//		int code = NotificationType.ORDER_NOTIFICATION.getValue();

//		parseNotice(userId, ordersList, notices, code, listToMap);

		// 添加订单通知
//		centerService.batchInsert(notices);

		// ---------------------

		parseManuscript(manuscripts, ordersList, time, id, userId);



		// 添加订单日志
		generateOrderLog(payManagerAddParam.getUserId(), ordersList, id, UserStatus.CREATED_ORDER.getStatusCode(),
				payManagerAddParam.getAssocId());

		if (result.useConpon) {

			User user = new User();

			user.setId((long) userId);

			user.setDuplicateCheckCoupon(result.duplicateCheckCoupon);

			userService.updateByPrimaryKeySelective(user);
		}

		orderResult.errorMsg = OrderErrorMsg.SUCCESS;

		orderResult.id = id;

		if (result.onlyDuplicateCheck) {
			orderResult.orderIds = new int[] {
					ordersList[0].getId()
			};
		}


//		orderResult.orderIds = Arrays.stream(ordersList).mapToInt(e->e.getId()).toArray();

		return orderResult;

	}

	@Override
	public <P extends IPayManagerServiceAddParam, M extends IManuscriptAddParam> ICodeAndData<Integer> placeAnOrder(
			IPayManagerAddParam<P, M> payManagerAddParam) {

		// 基础服务

		// 是否加急 计算加急费用

		// 获取当前服务价格

		// 论文查重 使用查重券？ 计算减免

		// 论文排版 按格式收费 处理

		// 推荐期刊 按篇数

		// 添加到订单表 、生成订单日志

		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

		TransactionStatus transactionStatus = platformTransactionManager.getTransaction(def);

		OrderResult orderResult;
		boolean useConpon = false;
		try {

			Map<Integer, List<ServicePriceConf>> listFromCache = this.priceConfService.getMapListFromCache();

			User userInfoToCache = userService.selectDuplicateCheckCoupon(payManagerAddParam.getUserId());

			SnowFlake snowFlake = new SnowFlake(0, 0);

			// 处理作图 -> 直接添加到 order 表里面

			P[] dataPlotting = payManagerAddParam.getDataPlotting();

			if (null != dataPlotting && 0 != dataPlotting.length) {

				M[] plottingManuscripts = payManagerAddParam.getPlottingManuscripts();

				if (null == plottingManuscripts || 0 == plottingManuscripts.length) {
					transactionStatus.setRollbackOnly();
					return new CodeAndData<Integer>(OrderErrorMsg.PLOTTING_MANUSCRIPTS.getMsg(),
							OrderErrorMsg.PLOTTING_MANUSCRIPTS.getCode(), 0);
				}
				int userId = payManagerAddParam.getUserId();
				byte p = 1;

				String orderNumber = OrderNumberGenerator.generateOrderNumber("ZF");

				Result ordersList = this.generateOrdersList(payManagerAddParam, dataPlotting, listFromCache,
						userInfoToCache, snowFlake, OrderStatus.PENDING_QUOTE.getStatusCode(), p, orderNumber);

				Order[] orders = ordersList.orders;
				useConpon = ordersList.useConpon;
				if (null == orders || 0 == orders.length) {

					transactionStatus.setRollbackOnly();
					return new CodeAndData<Integer>(OrderErrorMsg.NO_PLOTTING_SERVICE_ORDERS.getMsg(),
							OrderErrorMsg.NO_PLOTTING_SERVICE_ORDERS.getCode(), 0);
				}

				setPayManagerIdBYOrder(orders, 0);
//
				this.orderService.batchInsert(orders);

				this.generateOrderLog(userId, orders, 0, UserStatus.PENDING_QUOTE.getStatusCode(),
						payManagerAddParam.getAssocId());

				long time = System.currentTimeMillis() / 1000;

				this.parseManuscript(plottingManuscripts, orders, time, 0, userId);

				NoticeCenter[] notices = new NoticeCenter[orders.length];

				NoticeCenter noticeCenter;

				String contentPrefix = userInfoToCache.getRealname().concat("(ID:") + userInfoToCache.getId()
						+ ")提交【{TYPE_NAME}】订单{ORDER_SN},请及时查看处理!";

				List<ServiceManager> listToCache = serviceManager.listToCache(RedisConstant.SERVICCE_MANGER_KEY, 100);

				Map<Integer, ServiceManager> listToMap = ListConvertMap.listToMap(listToCache, ServiceManager::getId);

				ServiceManager serviceManager;

				int serviceId;

				long times = System.currentTimeMillis() / 1000;

				for (int i = 0; i < orders.length; i++) {

					noticeCenter = new NoticeCenter();

					noticeCenter.setUserId(userId);

					noticeCenter.setTypeId(orders[i].getId());

					serviceId = orders[i].getServiceId();

					serviceManager = listToMap.get(serviceId);

					if (null == serviceManager) {
						throw new IllegalArgumentException("添加通知时找不到服务id：" + serviceId);
					}

					contentPrefix = contentPrefix.replace("{TYPE_NAME}", serviceManager.getTypeName())
							.replace("{ORDER_SN}", orders[i].getOrderSnId());

					noticeCenter.setNoticeContent(contentPrefix);

					noticeCenter.setCreateTime(times);

					noticeCenter.setTitle("报价通知");
					;

					noticeCenter.setUpdateTime(times);

					noticeCenter.setPlatform((byte) 1);

					noticeCenter.setNoticeType((byte) 0);
					;

					notices[i] = noticeCenter;
				}

				// 添加订单通知
				centerService.batchInsert(notices);
			}

			byte zero = 0;
			orderResult = this.basicServices(payManagerAddParam, listFromCache, userInfoToCache, snowFlake, zero,useConpon);

			OrderErrorMsg msg = orderResult.errorMsg;

			if (!msg.equals(OrderErrorMsg.SUCCESS)) {
				transactionStatus.setRollbackOnly();
				return new CodeAndData<Integer>(msg.getMsg(), msg.getCode(), 0);
			}

			platformTransactionManager.commit(transactionStatus);

		} catch (Exception e) {
			logger.error("下单报错信息打印:"+ e.getMessage());
			e.printStackTrace();
			transactionStatus.setRollbackOnly();
			return new CodeAndData<Integer>(OrderErrorMsg.ERROR_MSG.getMsg(), OrderErrorMsg.ERROR_MSG.getCode(), 0);
		} finally {

			logger.debug("事务状态：{}", transactionStatus.isRollbackOnly());

			if (transactionStatus.isRollbackOnly()) {

				platformTransactionManager.rollback(transactionStatus);
			}
		}

		int resultId = orderResult.id;

		if (null != orderResult.orderIds && 1 == orderResult.orderIds.length) {
			// 返回订单id
			resultId = orderResult.orderIds[0];
		}

		return new CodeAndData<Integer>(OrderErrorMsg.SUCCESS.getMsg(), OrderErrorMsg.SUCCESS.getCode(),
				resultId);
	}

	private void generateOrderLog(int userId, Order[] order, Integer id, byte status, int assocId) {
		OrderLog[] orderLog = new OrderLog[order.length];

		long time = System.currentTimeMillis() / 1000;

		String requirement = "";

		if (0 != assocId) {
			Order selectByPrimaryKey = orderService.selectByPrimaryKey(assocId);

//			requirement += ":".concat(selectByPrimaryKey.getOrderSnId());
			requirement += selectByPrimaryKey.getOrderSnId();
		}

		byte userAndAdmin = 2;

		for (int j = 0; j < orderLog.length; j++) {

			orderLog[j] = new OrderLog();

			orderLog[j].setOrderId(order[j].getId());

			orderLog[j].setPayManagerId(id);

			orderLog[j].setUserId(userId);

			orderLog[j].setType(userAndAdmin);

			orderLog[j].setRequirement(requirement);

			orderLog[j].setCreateTime(time);

			orderLog[j].setOrderStatus(status);
		}

		this.orderLogService.batchInsert(orderLog);
	}

	/**
	 * 稿件
	 *
	 * @param <M>
	 * @param <P>
	 * @param payManagerAddParam
	 * @param order
	 * @param time
	 * @param id                 支付管理 id
	 */
	private <M extends IManuscriptAddParam> void parseManuscript(M[] manuscriptsParam, Order[] order, long time,
			Integer id, int userId) {

		// 处理稿件
		Manuscript[] manuscripts = new Manuscript[manuscriptsParam.length * order.length];

		Manuscript manuscript;

		int k = 0;

		String file, originlFile;

		for (int i = 0; i < order.length; i++) {

			for (int j = 0; j < manuscriptsParam.length; j++) {

				manuscript = new Manuscript();

				manuscript.setCreateTime(time);

				originlFile = manuscriptsParam[j].getFile();

				file = common(originlFile);

				manuscript.setFile(file);

				manuscript.setOrderId(order[i].getId());

				manuscript.setPayManagerId(id);

				manuscript.setUserId(userId);

				manuscript.setOriginName(manuscriptsParam[j].getOriginName());

				manuscript.setSize(manuscriptsParam[j].getSize());

				manuscript.setUpdateTime(time);

				manuscripts[k] = manuscript;
				k++;
			}
		}

		manuscriptService.batchInsert(manuscripts);
	}

	private String common(String pic) {

		String prefix = (config.getNoPerfixURL());

		return pic.replaceAll("http://", "").replaceAll("https://", "").replaceAll(prefix, "");

	}

	/**
	 * 设置订单paymanager id
	 *
	 * @param order
	 * @param id
	 */
	private void setPayManagerIdBYOrder(Order[] order, int id) {

		for (int i = 0; i < order.length; i++) {

			order[i].setPayManagerId(id);
		}
	}

	/**
	 *
	 * @param <P>
	 * @param userInfoToCache
	 * @param wordSizePrice
	 * @param item
	 * @param time
	 * @param statusCode
	 * @param snowFlake
	 * @param zeroStatus
	 * @param p
	 * @param wordSize        字数 或篇数
	 * @param type            服务类型 0 基础服务 1 数据作图与科研绘图服务
	 * @param serviceId       服务类型id
	 */
	private <P extends IPayManagerServiceAddParam> void createOrderItem(User userInfoToCache, BigDecimal wordSizePrice,
			Order item, long time, byte statusCode, SnowFlake snowFlake, byte zeroStatus, P p, Integer wordSize,
			Byte type, int serviceId) {

		Integer teamId = userInfoToCache.getTeamId();

		if (1 != userInfoToCache.getStatus()) {
			teamId = 0;
		}

		item.setServiceId(serviceId);

		item.setUserId(userInfoToCache.getId().intValue());

		item.setWordSize(p.getWordSize());

		item.setRecommendNumber(p.getRecommendNumber());

		item.setServicePrice(wordSizePrice);

		item.setCommentStatus(false);

		item.setProgramme(p.getProgramme());

		String article = p.getArticle();
		item.setArticle(null == article ? "" : article);

		item.setCreateTime(time);

		item.setServiceType(type);

		item.setOrderStatus(statusCode);

		item.setUserStatus(statusCode);

		item.setEditStatus(EditStatus.PENDING.getStatusCode());

		Byte format = p.getFormat();
		item.setFormat(null == format ? 2 : format);

		item.setOrderType(false);

		item.setPlatform(zeroStatus);

		String professionalField = p.getProfessionalField();
		item.setProfessionalField(null == professionalField ? "" : professionalField);

		item.setRemarks(p.getRemarks());
		item.setPayType(p.getPayType());

		item.setTargetJournal(p.getTargetJournal());

		item.setTeamId(teamId);

		item.setWordSize(wordSize);

	}

}
